const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// 压缩css
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const EslintWebpackPlugin = require('eslint-webpack-plugin')

process.env.NODE_ENV = 'production'
/**
 * 在开发环境中开启HMR功能，能够解决一个模块改变只构建这一个模块（模块热替换），其他模块不构建。
 * 在生产环境中也有类似的方案。对第一次构建的文件进行缓存，第二次构建时，如果没有变化直接读取缓存，只构建改变的模块。提升构建速度。
 *
 * 缓存：
 *    babel 缓存：
 *      cacheDirectory: true
 *      --> 让第二次打包构建速度更快。babel转换后的文件会做缓存，如果文件不变第二次就会从缓存中取
 *    文件资源缓存：
 *      hash：每次webpack构建都会生成一个hash值
 *        问题：因为js和css同时使用一个hash值。如果重新打包，会导致所有的缓存失效。（可能我只改动一个文件）
 *      chunkhash: 根据chunk生成的hash。如果打包来源同一个chunk，那么hash值就一样。
 *        问题：js和css的hash值还是一样的。因为css实在js中引入的，所以同属一个chunk
 *      contenthash: 根据文件内容生成hash，不同文件的hash值一定不同。
 *      --> 让上线代码缓存更好
 * */

/**
 * tree shaking： 去除无用代码
 *    前提：1.必须使用 ES6 模块化 2. 开启 production 环境
 *    作用：减少代码体积
 *
 *    如果在 package.json 中配置
 *      "sideEffects" : false
 *      所有的代码都没有副作用（都可以进行 tree shaking）
 *        问题：可能会把 css / @babel/polyfill (副作用) 文件干掉
 *      所以为了保险这样配置：
 *      "sideEffects": ["*.css", "*.less"]
 *
 * */

const commonCssLoader = [
  MiniCssExtractPlugin.loader,
  'css-loader',
  {
    loader: "postcss-loader",
    options: {
      postcssOptions: {
        plugins: [
          // 需要在package.json中配置browserslist
          'postcss-preset-env'
        ]
      }
    }
  }
]

module.exports = {
  entry: './src/index.js',
  output: {
    filename: "js/[name].bundle.[contenthash:10].js",
    path: resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      // js语法检查
      {
        test: /\.js$/,
        // 优先执行（多个loader处理同一种文件时，该属性决定优先执行）
        enforce: "pre",
        exclude: /node_modules/
      },
      {
        /*
        * 以下loader只会匹配一个
        * 注意：不能有两个loader处理同一个类型的文件
        * */
        oneOf: [
          // 样式处理
          {
            test: /\.css$/,
            use: [...commonCssLoader]
          },
          {
            test: /\.less$/,
            use: [...commonCssLoader, 'less-loader']
          },
          // js 兼容性处理
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel-loader",
            options: {
              presets: [
                [
                  '@babel/preset-env',
                  {
                    useBuiltIns: 'usage',
                    corejs: {
                      version: 3
                    },
                    targets: {
                      chrome: '60',
                      firefox: '60',
                      ie: '9',
                      safari: '10',
                      edge: '17'
                    }
                  }
                ]
              ],
              /*
              * 开启babel缓存
              * 第二次构建时会读取之前的缓存
              * */
              cacheDirectory: true
            }
          },
          // 处理图片资源
          {
            test: /\.(png|jpg|gif)$/,
            loader: "url-loader", // 依赖file-loader
            options: {
              limit: 10 * 1024,
              outputPath: 'imgs',
              name: "[hash:10].[ext]",
              esModule: false
            },
            type: 'javascript/auto'
          },
          {
            test: /\.html$/,
            loader: 'html-loader'
          },

          // 处理其他资源
          {
            exclude: /\.(js|css|less|png|jpg|gif)$/,
            type: 'asset/resource'
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/template.html",
      // 压缩
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    }),
    new MiniCssExtractPlugin({
      filename: 'css/[contenthash:10].css'
    }),
    new OptimizeCssAssetsWebpackPlugin(),
    new EslintWebpackPlugin({
      fix: true
    })
  ],
  mode: "production"
}